package JDK常用类库.stream;

import org.junit.Test;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;

/**
 * @Author：russ
 * @Date：2023/8/16
 * @apiNote：Java8新的时间日期API
 */
public class DateTimeTest {
    /**
     * JDK8日期时间操作：LocalDate
     */
    @Test
    public void test1(){
        // 1.创建指定的日期
        LocalDate date1 = LocalDate.of(2021, 03, 02);
        System.out.println("date1 = " + date1);

        // 2.得到当前的日期
        LocalDate now = LocalDate.now();
        System.out.println("now = " + now);

        // 3.根据LocalDate对象获取对应的日期信息
        System.out.println("年：" + now.getYear());
        System.out.println("月：" + now.getMonth().getValue());
        System.out.println("日：" + now.getDayOfMonth());
        System.out.println("星期：" + now.getDayOfWeek().getValue());
    }

    /**
     * 时间操作：LocalTime
     */
    @Test
    public void test2(){
        // 1.得到指定的时间
        LocalTime time = LocalTime.of(5,26,33,23145);
        System.out.println(time);
        // 2.获取当前的时间
        //从默认时区的系统时钟获取当前的日期时间
        LocalTime now = LocalTime.now();
        System.out.println(now);
        // 3.获取时间信息
        System.out.println(now.getHour());
        System.out.println(now.getMinute());
        System.out.println(now.getSecond());
        System.out.println(now.getNano());
    }

    /**
     * 日期时间类型：LocalDateTime
     */
    @Test
    public void test3(){
        // 获取指定的日期时间
        LocalDateTime dateTime = LocalDateTime.of(2023, 07, 01, 22, 18, 23, 410416);
        System.out.println(dateTime);
        // 获取当前的日期时间
        //从默认时区的系统时钟获取当前的日期时间
        LocalDateTime now = LocalDateTime.now();
        //美国洛杉矶时间
        LocalDateTime now2 = LocalDateTime.now(ZoneId.of("America/Los_Angeles"));
        System.out.println(now);
        System.out.println(now2);
        // 获取日期时间信息
        System.out.println(now.getYear());
        System.out.println(now.getMonth().getValue());
        System.out.println(now.getDayOfMonth());
        System.out.println(now.getDayOfWeek().getValue());
        System.out.println(now.getHour());
        System.out.println(now.getMinute());
        System.out.println(now.getSecond());
        System.out.println(now.getNano());
    }

    /**
     * 日期时间的修改
     *
     * 注意：在进行日期时间修改时,原来的LocalDateTime对象不会被修改,每次操作都返回一个新的LocalDateTime对象,所以在多线程场景下是数据安全的
     */
    @Test
    public void test4(){
        LocalDateTime now = LocalDateTime.now();
        System.out.println("now = " + now);
        LocalDateTime localDateTime = now.withYear(2021);
        System.out.println("now :" + now);
        System.out.println("修改后的：" + localDateTime);

        System.out.println("月份：" + now.withMonth(10));
        System.out.println("天：" + now.withDayOfMonth(4));
        System.out.println("小时：" + now.withHour(16));
        System.out.println("分钟:" + now.withMinute(23));

        // 在当前日期时间的基础上，加上或者减去指定的时间
        System.out.println("两天后:" + now.plusDays(2));
        System.out.println("10年后:"+ now.plusYears(10));
        System.out.println("6个月后 = " + now.plusMonths(6));

        System.out.println("10年前 = " + now.minusYears(10));
        System.out.println("半年前 = " + now.minusMonths(6));
        System.out.println("一周前 = " + now.minusDays(7));
    }

    /**
     * 日期时间的比较
     * 在JDK8中通过isAfter()、isBefore()、isEqual()这几个方法实现日期的比较
     */
    @Test
    public void test5(){
        LocalDate now = LocalDate.now();
        LocalDate date = LocalDate.of(2001, 4, 16);
        System.out.println(now.isAfter(date));// true
        System.out.println(now.isBefore(date));// false
        System.out.println(now.isEqual(date));// false

        LocalDateTime nowTime = LocalDateTime.now();
        LocalDateTime dateTime = LocalDateTime.of(2023,7,02,22,18,10);
        System.out.println(nowTime.isAfter(dateTime));
        System.out.println(nowTime.isBefore(dateTime));
        System.out.println(nowTime.isEqual(dateTime));
    }

    /**
     * 格式化和解析操作
     * 在JDK8中通过java.time.format.DateTimeFormatter类进行日期的解析和格式化操作
     */
    @Test
    public void test6(){
        LocalDateTime now = LocalDateTime.now();
        // 指定格式(使用系统默认的格式)：2021-05-27T16:16:38.139
        DateTimeFormatter isoLocalDateTime = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        // 将日期时间转换为字符串
        String format = now.format(isoLocalDateTime);
        System.out.println("format = " + format);

        // 通过ofPattern()来指定特定的格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format1 = now.format(dateTimeFormatter);
        // 2021-05-27 16:16:38
        System.out.println("format1 = " + format1);

        // 将字符串解析为日期时间类型
        // 从一个文本字符串(如 2007-12-03T10:15:30)中获取一个 LocalDateTime的实例
        LocalDateTime dateTime5 = LocalDateTime.parse("2020-12-14T12:00:50");
        // 使用特定的格式化 LocalDateTime从文本字符串获取 LocalDateTime的实例
        LocalDateTime parse = LocalDateTime.parse("2023-07-01 22:18:23", dateTimeFormatter);
        // parse = 2023-07-01T22:18:23
        System.out.println("parse = " + parse);
    }

    /**
     * 在JDK8中新增Instant类(时间戳), 内部保存了从1970年1月1日 00:00:00以来的秒和纳秒。
     */
    @Test
    public void test8()throws Exception{
        LocalDateTime now2 = LocalDateTime.now();
        System.out.println("now2 = " + now2);
        Instant now = Instant.now();//和LocalDateTime作比较，发现Instant和当前时区有8个小时时差
        System.out.println("now = " + now);

        // 获取从1970年一月一日 00:00:00 到现在的 纳秒
        System.out.println(now.getNano());
        Thread.sleep(5);
        Instant now1 = Instant.now();
        System.out.println("历经：" + (now1.getNano() - now.getNano()));

        System.out.println();
        //从1970年1月1日 00:00:00以来的秒(获取当前时间戳)
        Long seconds = Instant.ofEpochSecond(0L).until(Instant.now(), ChronoUnit.SECONDS);
        System.out.println("Seconds since the beginning of the Java epoch = " + seconds);
        System.out.println(seconds / 24 / 3600);//天数
        System.out.println(seconds / 24 / 3600 / 365);//年数
    }

    /**
     * 将时间戳转为指定格式时间
     * 使用java.time.LocalDateTime类（Java 8及以上版本）
     */
    @Test
    public void test12(){
        // 将时间戳转换为LocalDateTime对象
        long timestamp = 1612345678901L; // 时间戳，单位为毫秒
        Instant instant = Instant.ofEpochMilli(timestamp);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        // 将LocalDateTime对象转换为指定格式的字符串
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 定义日期格式
        String formattedDateTime = dateTime.format(formatter);
        System.out.println(formattedDateTime);
    }

    /**
     * JDK8中提供了两个工具类Duration/Period：计算日期时间差
     *
     * Duration：用来计算两个时间差(LocalTime)
     * Period:用来计算两个日期差(LocalDate)
     */
    @Test
    public void test9(){
        // 计算时间差
        LocalTime now = LocalTime.now();
        LocalTime time = LocalTime.of(23, 10, 16);
        System.out.println("now = " + now);
        Duration duration = Duration.between(now, time);
        System.out.println(duration.toDays());
        System.out.println(duration.toHours());
        System.out.println(duration.toMinutes());
        System.out.println(duration.toMillis());

        // 计算日期差
        LocalDate nowDate = LocalDate.now();
        LocalDate date = LocalDate.of(2001, 4, 16);
        Period period = Period.between(date, nowDate);
        System.out.println(period.getYears());
        System.out.println(period.getMonths());
        System.out.println(period.getDays());
    }

    /**
     * 有时候需要如下调整：将日期调整到"下个月的第一天"等操作。
     *
     * TemporalAdjuster:时间校正器
     * TemporalAdjusters:通过该类静态方法提供了大量的常用TemporalAdjuster的实现
     */
    @Test
    public void test10(){
        LocalDateTime now = LocalDateTime.now();
        // 将当前的日期调整到下个月的一号
        TemporalAdjuster adJuster = temporal -> {
            LocalDateTime dateTime = (LocalDateTime) temporal;
            LocalDateTime nextMonth = dateTime.plusMonths(1).withDayOfMonth(1);
            System.out.println("nextMonth = " + nextMonth);
            return nextMonth;
        };

        LocalDateTime nextMonth = now.with(TemporalAdjusters.firstDayOfNextMonth());
        System.out.println("nextMonth = " + nextMonth);
    }

    /**
     * Java8 中加入了对时区的支持, LocalDate、LocalTime、LocalDateTime是不带时区的
     * 带时区的日期时间类分别为：ZonedDate、ZonedTime、ZonedDateTime
     * 其中每个时区都对应着ID, ID的格式为 “区域/城市” 。例如 ：Asia/Shanghai 等
     * ZoneId：该类中包含了所有的时区信息。
     */
    @Test
    public void test11(){
        // 获取所有的时区id
        // ZoneId.getAvailableZoneIds().forEach(System.out::println);

        // 获取当前时间(中国使用的东八区的时区, 比标准时间早8个小时)
        LocalDateTime now = LocalDateTime.now();
        System.out.println("now = " + now);
        // 获取标准时间
        ZonedDateTime bz = ZonedDateTime.now(Clock.systemUTC());
        System.out.println("标椎 = " + bz);

        // 使用计算机默认的时区, 创建日期时间
        ZonedDateTime now1 = ZonedDateTime.now();
        System.out.println("now1 = " + now1);

        // 使用指定的时区创建日期时间
        ZonedDateTime now2 = ZonedDateTime.now(ZoneId.of("America/Marigot"));
        System.out.println("now2 = " + now2);
    }
}
